﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Common;
using Common.Config;
using Common.Model;
using ConsoleService.Helps;
using ConsoleService.Model;
using HtmlAgilityPack;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;

namespace ConsoleService.API
{
    public class CommonAPI
    {
        Logger logger = LogManager.GetCurrentClassLogger();
        public CommonAPI()
        {
            NLog.Web.NLogBuilder.ConfigureNLog("nlog.config");
        }


        #region 爬取公司数据

        ///   <summary>
        ///  获取指定URL的HTML源代码
        ///   </summary>
        ///   <param name="url"></param>
        ///   <param name="encoding"> 如果为NULL 则自动识别 </param>
        ///   <returns></returns>
        public string GetWebHtml(string url, Encoding encoding)
        {
            try
            {
                HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create(url);
                hwr.UserAgent = "Foo";
                hwr.Accept = "*/*";
                HttpWebResponse res;

                try
                {
                    res = (HttpWebResponse)hwr.GetResponse();
                }
                catch (Exception ex)
                {
                    return string.Empty;
                }

                if (res.StatusCode == HttpStatusCode.OK)
                {
                    using (Stream mystream = res.GetResponseStream())
                    {
                        // 没有指定编码，
                        if (encoding == null)
                        {
                            return DecodeData(mystream, res);
                        }
                        // 指定了编码
                        else
                        {
                            using (StreamReader reader = new StreamReader(mystream, encoding))
                            {
                                return reader.ReadToEnd();
                            }
                        }
                    }
                }

                return null;
            }
            catch
            {
                return null;
            }
        }


        private string DecodeData(Stream responseStream, HttpWebResponse response)
        {
            string name = null;
            string text2 = response.Headers["content-type"];
            if (text2 != null)
            {
                int index = text2.IndexOf("charset=");
                if (index != -1)
                {
                    name = text2.Substring(index + 8);
                }
            }
            MemoryStream stream = new MemoryStream();
            byte[] buffer = new byte[0x400];
            for (int i = responseStream.Read(buffer, 0, buffer.Length); i > 0; i = responseStream.Read(buffer, 0, buffer.Length))
            {
                stream.Write(buffer, 0, i);
            }
            responseStream.Close();
            if (name == null)
            {
                MemoryStream stream3 = stream;
                stream3.Seek((long)0, SeekOrigin.Begin);
                string text3 = new StreamReader(stream3, Encoding.ASCII).ReadToEnd();
                if (text3 != null)
                {
                    int startIndex = text3.IndexOf("charset=");
                    int num4 = -1;
                    if (startIndex != -1)
                    {
                        num4 = text3.IndexOf(" \" ", startIndex);
                        if (num4 != -1)
                        {
                            int num5 = startIndex + 8;
                            name = text3.Substring(num5, (num4 - num5) + 1).TrimEnd(new char[] { '>', '"' });
                        }
                    }
                }
            }
            Encoding aSCII = null;
            if (name == null)
            {
                aSCII = Encoding.GetEncoding("gb2312");
            }
            else
            {
                try
                {
                    if (name == "GBK")
                    {
                        name = "GB2312";
                    }
                    aSCII = Encoding.GetEncoding(name);
                }
                catch
                {
                    aSCII = Encoding.GetEncoding("gb2312");
                }
            }
            stream.Seek((long)0, SeekOrigin.Begin);
            StreamReader reader2 = new StreamReader(stream, aSCII);
            return reader2.ReadToEnd();
        }

        public void Test()
        {
            string url = "https://www.tianyancha.com/search?key=UTMS&sessionNo=1657876701.61849509";
            HtmlWeb Webget = new HtmlWeb();
            HtmlDocument doc = new HtmlDocument();
            Webget.AutoDetectEncoding = false;
            Webget.OverrideEncoding = Encoding.UTF8;

            doc.OptionOutputAsXml = true;
            doc.OptionReadEncoding = true;
            doc.OptionFixNestedTags = true;
            doc.OptionDefaultStreamEncoding = Encoding.UTF8;

            doc.LoadHtml(Webget.Load(url).Text);
            doc.Save(Console.Out);

            //HtmlWeb baseWeb = new HtmlWeb();

            //var basehtmlDoc = baseWeb.Load(url);
            //var html = GetWebHtml(url, null);
            //var html2 = WebHelper.HttpRequest(url);

        }

        public void GetSearchCompany(List<string> keys, bool issame = true)
        {

            List<Company> list = new List<Company>();

            // Test();
            int index = 1;

            //公司关键字查询
            keys.ForEach(z =>
            {

                try
                {
                    HtmlWeb baseWeb = new HtmlWeb();
                    var search = $"https://www.tianyancha.com/search?key={z}";

                    var basehtmlDoc = baseWeb.Load(search);

                    //获取根节点的dom元素
                    var basebody = basehtmlDoc.DocumentNode.SelectSingleNode("//div[@class='index_list-wrap___axcs']");

                    if (basebody != null)
                    {
                        //便利根节点dom元素
                        var roots = basebody.SelectNodes("//div[@class='index_name__qEdWi']");

                        if (roots != null)
                        {
                            foreach (var item in roots)
                            {
                                //获取公司名称
                                var company = item.InnerText;


                                //过滤掉公司名称不统一情况
                                if (!(z == company) && issame)
                                {
                                    continue;
                                }

                                //获取dom子元素
                                var child = item.ChildNodes;

                                foreach (var c in child)
                                {
                                    HtmlAttributeCollection attrs = c.Attributes;
                                    foreach (var a in attrs)
                                    {
                                        //解析超链接
                                        if (a.Name == "href")
                                        {
                                            logger.Warn($"{index}.{company}---{a.Value}");
                                            Console.WriteLine($"{index}.{company}---{a.Value}");
                                            var result = GetCompanyDetail(a.Value);
                                            if (result != null)
                                            {
                                                list.Add(result);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    index++;
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"解析失败：{ex.Message}");
                    logger.Error($"解析失败：{ex.Message}", ex);
                }
                finally
                {

                }

            });

            if (list.Count > 0)
            {
                UpdateCompany(list);
            }
            else
            {
                Console.WriteLine($"未获取数据");
                logger.Error($"未获取数据");
            }

        }


        public Company GetCompanyDetail(string url)
        {

            try
            {
                HtmlWeb web = new HtmlWeb();
                var htmlDoc = web.Load(url);
                var body = htmlDoc.DocumentNode.SelectSingleNode("//body[@id='important']");
                if (body == null)
                {
                    Console.WriteLine($"解析明细为空！");
                    logger.Error($"解析明细为空！");
                    return null;
                }
                var childNodes = body.ChildNodes;
                //遍历所有的html节点
                foreach (var item in childNodes)
                {
                    if (item.Name == "script")
                    {
                        var jo = JObject.Parse(item.InnerText);

                        var json = jo["props"]["pageProps"]["dehydratedState"]["queries"][0]["state"]["data"]["data"].ToString();

                        var entity = JsonConvert.DeserializeObject<Data>(json);

                        var company = new Company();

                        var result = Help.ConvertToMap(company, entity);
                        company.tianyancha_Id = entity.id.ToString();
                        if (entity.approvedTime.HasValue && entity.approvedTime > 0)
                        {
                            result.approvedTime = Help.ToLocalTimeDateByMilliseconds(entity.approvedTime.Value);
                        }

                        if (entity.updateTimes.HasValue && entity.updateTimes > 0)
                        {
                            result.updateTimes = Help.ToLocalTimeDateByMilliseconds(entity.updateTimes.Value);
                        }

                        if (entity.fromTime.HasValue && entity.fromTime > 0)
                        {
                            result.fromTime = Help.ToLocalTimeDateByMilliseconds(entity.fromTime.Value);
                        }

                        if (entity.toTime.HasValue && entity.toTime > 0)
                        {
                            result.toTime = Help.ToLocalTimeDateByMilliseconds(entity.toTime.Value);
                        }

                        logger.Warn("解析成功");
                        Console.WriteLine("解析成功！");
                        return result;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"解析失败：{ex.Message}");
                logger.Error($"解析失败：{ex.Message}", ex);
                return null;
            }
            finally
            {

            }

        }

        public void UpdateCompany(List<Company> list)
        {
            var log = $"解析公司数据共计：{list.Count}，开始调用接口写入数据库...";
            Console.WriteLine(log);
            logger.Warn(log);

            var api = new UserAPI();
            var currentUser = api.GetUserToken();
            var Token = currentUser.data.Token;

            //写入数据库
            Dictionary<string, string> parameters = new Dictionary<string, string>();
            parameters.Add("Json", list.ToJson());
            RequestModel request = new RequestModel()
            {
                Method = RestSharp.Method.POST,
                Parameters = parameters,
                Token = Token,
                Resources = "/api/Common/UpdateCompay",
                WebSide = Configs.WebUrl,
            };

            RabbitMQUtil.SendDelayMessage(new DelayMessageModel() { JsonData = request.ToJson(), DelayTime = 1000 });
            //var response = WebHelper.HttpRequest(request);
            //Console.WriteLine("接口调用公司数据写入成功！" + response);
            //logger.Warn("接口调用公司数据写入成功！" + response);
        }
        #endregion

        public List<Company> GetCompanyList(DateTime? start = null, DateTime? stop = null, int rows = 5000)
        {
            var api = new UserAPI();
            var currentUser = api.GetUserToken();
            var Token = currentUser.data.Token;
            Dictionary<string, string> parameters = new Dictionary<string, string>();
            parameters.Add("page", "1");
            parameters.Add("rows", rows.ToString());
            parameters.Add("sidx", "CreatedTime");
            parameters.Add("sord", "desc");

            if (start.HasValue)
            {
                parameters.Add("StartDate", start.Value.ToString());
            }

            if (stop.HasValue)
            {
                parameters.Add("EndDate", stop.Value.ToString());
            }

            RequestModel request = new RequestModel()
            {
                Method = RestSharp.Method.GET,
                Parameters = parameters,
                Token = Token,
                Resources = "/api/Common/GetCompanyList",
                WebSide = Configs.WebUrl,
            };
            var result = WebHelper.HttpRequest<CompanyResult>(request);
            return result.data.rows;
        }

        public CompanyResult GetCompanyList2(int page = 1, int rows = 100)
        {
            var api = new UserAPI();
            var currentUser = api.GetUserToken();
            var Token = currentUser.data.Token;
            Dictionary<string, string> parameters = new Dictionary<string, string>();
            parameters.Add("page", page.ToString());
            parameters.Add("rows", rows.ToString());
            //parameters.Add("keyWord", "长沙");
            parameters.Add("sidx", "CreatedTime");
            parameters.Add("sord", "asc");
            RequestModel request = new RequestModel()
            {
                Method = RestSharp.Method.GET,
                Parameters = parameters,
                Token = Token,
                Resources = "/api/Common/GetCompanyList",
                WebSide = Configs.WebUrl,
            };
            var result = WebHelper.HttpRequest<CompanyResult>(request);
            return result;
        }


        public bool GetOilPrice(string Token)
        {
            try
            {
                if (string.IsNullOrEmpty(Token))
                {
                    UserAPI api = new UserAPI();
                    var currentUser = api.GetUserToken();
                    Token = currentUser.data.Token;
                }


                Console.WriteLine("开始解析服务器地址：http://www.qiyoujiage.com/");
                logger.Warn("开始解析服务器地址：http://www.qiyoujiage.com/");

                var url = "http://www.qiyoujiage.com";

                HtmlWeb web = new HtmlWeb();

                var htmlDoc = web.Load(url);
                var node = htmlDoc.DocumentNode.SelectSingleNode("//div[@id='left']//ul[@class='ylist']");

                HtmlNodeCollection CNodes = node.ChildNodes;    //所有的子节点
                                                                //Console.WriteLine("Node Name: " + node.Name + "\n" + node.OuterHtml);

                IDictionary<string, decimal> dict = new Dictionary<string, decimal>();
                List<string> MyList = new List<string>();

                List<OilPrice> MyOilPrice = new List<OilPrice>();

                foreach (HtmlNode item in CNodes)
                {
                    HtmlAttributeCollection attrs = item.Attributes;
                    //判断是否有class属性
                    if (attrs.Count == 0)
                    {
                        MyList.Add(item.InnerText);
                    }
                    else
                    {
                        foreach (var c in attrs)
                        {
                            //Console.WriteLine(c.Name + " : " + c.Value);    //输出 class ：user_match clear

                            //抓取数据
                            if (c.Value == "t")
                            {
                                MyList.Add(item.InnerText);
                            }
                        }
                    }
                    //Console.WriteLine(item.Name + "-" + item.InnerText);  //输出 li-年龄：21～30之间#text-   li-婚史：未婚#text-     .......  别忘了文本节点也算
                }

                int index = 0;
                int Order = 1;
                string Provinces = "";
                decimal Gasoline_92 = 0;
                decimal Gasoline_95 = 0;
                decimal Gasoline_98 = 0;
                foreach (var item in MyList)
                {

                    if (index == 0)
                    {
                        Provinces = item;
                        Order += 1;
                        index += 1;
                        continue;
                    }
                    else if (index == 1)
                    {
                        Gasoline_92 = string.IsNullOrEmpty(item) ? 0 : Convert.ToDecimal(item);
                        index += 1;
                        continue;
                    }
                    else if (index == 2)
                    {
                        Gasoline_95 = string.IsNullOrEmpty(item) ? 0 : Convert.ToDecimal(item);
                        index += 1;
                        continue;
                    }
                    else if (index == 3)
                    {
                        Gasoline_98 = string.IsNullOrEmpty(item) ? 0 : Convert.ToDecimal(item);
                        index += 1;
                        continue;
                    }
                    else if (index == 4)
                    {
                        decimal Diesel = string.IsNullOrEmpty(item) ? 0 : Convert.ToDecimal(item);
                        index = 0;
                        MyOilPrice.Add(new OilPrice()
                        {
                            Provinces = Provinces,
                            Diesel = Diesel,
                            Gasoline_92 = Gasoline_92,
                            Gasoline_95 = Gasoline_95,
                            Gasoline_98 = Gasoline_98,
                            Order = Order
                        });
                        continue;
                    }
                }

                if (MyOilPrice.Count > 0)
                {
                    //写入数据库
                    Dictionary<string, string> parameters = new Dictionary<string, string>();
                    parameters.Add("Json", MyOilPrice.ToJson());
                    RequestModel request = new RequestModel()
                    {
                        Method = RestSharp.Method.POST,
                        Parameters = parameters,
                        Token = Token,
                        Resources = "/api/Common/AddOilPrice",
                        WebSide = Configs.WebUrl,
                    };
                    var response = WebHelper.HttpRequest(request);
                    Console.WriteLine("油价数据写入成功！" + MyOilPrice.Count);
                    return true;
                }
                else
                {
                    logger.Warn("同步油价数据为空！");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"同步油价数据异常：{ex.Message}");
                logger.Error($"同步油价数据异常：{ex.Message}", ex);
                return false;
            }
        }

        public bool GetOilPrice2(string Token)
        {
            try
            {
                if (string.IsNullOrEmpty(Token))
                {
                    UserAPI api = new UserAPI();
                    var currentUser = api.GetUserToken();
                    Token = currentUser.data.Token;
                }

                var url = "https://datacenter.cngold.org/city_oil/all_price_by_year/";
                var result = WebHelper.HttpRequest(url);
                var data = JsonConvert.DeserializeObject<OilRoot>(result);

                if (data != null)
                {
                    List<OilPrice> MyOilPrice = new List<OilPrice>();
                    var todayList = data.data.Where(c => c.date.ToString("yyyy-MM-dd") == DateTime.Now.ToString("yyyy-MM-dd")).ToList();
                    foreach (var item in todayList)
                    {
                        var a = 0M;
                        var b = 0M;
                        var c = 0M;
                        var d = 0M;
                        MyOilPrice.Add(new OilPrice()
                        {
                            Provinces = item.regionName.Replace("市", "").Replace("省", "").Trim(),
                            Gasoline_92 = decimal.TryParse(item.n92, out a) ? a : 0,
                            Gasoline_95 = decimal.TryParse(item.n95, out b) ? b : 0,
                            Gasoline_98 = decimal.TryParse(item.n98, out c) ? c : 0,
                            Diesel = decimal.TryParse(item.n89, out d) ? d : 0,
                        });
                    }

                    if (MyOilPrice.Count > 0)
                    {
                        //写入数据库
                        Dictionary<string, string> parameters = new Dictionary<string, string>();
                        parameters.Add("Json", MyOilPrice.ToJson());
                        RequestModel request = new RequestModel()
                        {
                            Method = RestSharp.Method.POST,
                            Parameters = parameters,
                            Token = Token,
                            Resources = "/api/Common/AddOilPrice",
                            WebSide = Configs.WebUrl,
                        };
                        var response = WebHelper.HttpRequest(request);
                        Console.WriteLine("油价数据写入成功！" + MyOilPrice.Count);
                        return true;
                    }
                    else
                    {
                        logger.Warn("同步油价数据为空！");
                        return false;
                    }
                }
                logger.Warn("同步油价数据为空！");
                return false;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public bool GetOilPrice3(string Token)
        {

            try
            {
                if (string.IsNullOrEmpty(Token))
                {
                    UserAPI api = new UserAPI();
                    var currentUser = api.GetUserToken();
                    Token = currentUser.data.Token;
                }

                Console.WriteLine("开始解析服务器地址：https://oil.nbsasu.com/oilprice/");
                logger.Warn("开始解析服务器地址：https://oil.nbsasu.com/oilprice/");
                var url = "https://oil.nbsasu.com/oilprice/";
                var web = new HtmlWeb();
                var htmlDoc = web.Load(url);
                var node = htmlDoc.DocumentNode.SelectSingleNode("//div[@class='table-container']");

                var MyOilPrice = new List<OilPrice>();

              

                var table = node.SelectSingleNode("//table[@class='layui-table']");
                var tbody = table.SelectNodes("tbody");

                foreach (var item in tbody.Nodes())
                {
                    //获取dom子元素
                    var child = item.ChildNodes;
                    if (child != null)
                    {
                        var tempArr = child.Where(c => !string.IsNullOrEmpty(c.InnerText) && !string.IsNullOrWhiteSpace(c.InnerText)).ToList();
                        if (tempArr != null && tempArr.Count == 6)
                        {
                            var today = tempArr[5].InnerText;//更新时间
                            if (DateTime.Now.Subtract(Convert.ToDateTime(today)).Days == 0)
                            {
                                var a = 0M;
                                var b = 0M;
                                var c = 0M;
                                var d = 0M;
                                MyOilPrice.Add(new OilPrice()
                                {
                                    Provinces = tempArr[0].InnerText,
                                    Gasoline_92 = decimal.TryParse(tempArr[1].InnerText, out a) ? a : 0,
                                    Gasoline_95 = decimal.TryParse(tempArr[2].InnerText, out b) ? b : 0,
                                    Gasoline_98 = decimal.TryParse(tempArr[3].InnerText, out c) ? c : 0,
                                    Diesel = decimal.TryParse(tempArr[4].InnerText, out d) ? d : 0,
                                });
                            }
                            else
                            {
                                Console.WriteLine("当天油价未更新");
                                logger.Warn("当天油价未更新");
                                return false;
                            }
                        }
                    }
                }

                if (MyOilPrice.Count > 0)
                {
                    //写入数据库
                    Dictionary<string, string> parameters = new Dictionary<string, string>();
                    parameters.Add("Json", MyOilPrice.ToJson());
                    RequestModel request = new RequestModel()
                    {
                        Method = RestSharp.Method.POST,
                        Parameters = parameters,
                        Token = Token,
                        Resources = "/api/Common/AddOilPrice",
                        WebSide = Configs.WebUrl,
                    };
                    var response = WebHelper.HttpRequest(request);
                    Console.WriteLine("油价数据写入成功！" + MyOilPrice.Count);

                    var model = new EmailModel();
                    model.Subject = DateTime.Now.ToString("yyyy年MM月dd日") + "汽油油价列表";
                    model.Context = node.InnerHtml;
                    model.To = new List<string>() { "1294833881@qq.com" };
                    model.Cc = new List<string>() { "2653859300@qq.com" };
                    model.IsHtml = true;
                    RabbitMQUtil.SendMessage(model.ToJson(), "emailQueue");

                    return true;
                }
                else
                {
                    logger.Warn("同步油价数据为空！");
                    return false;
                }

            }
            catch (Exception ex)
            {
                return false;
            }
        }
    }
}
